#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@ProjectName: Homalos
@FileName   : utility
@Date       : 2025/5/28 15:03
@Author     : Donny
@Email      : donnymoving@gmail.com
@Software   : PyCharm
@Description: General utility functions.
"""
import json
import re
import sys
from configparser import ConfigParser
from decimal import Decimal
from math import ceil, floor
from pathlib import Path
from zoneinfo import ZoneInfo, available_timezones  # noqa

from src.config.constant import Exchange
from ..config.params import Params


def del_num(content):
    """
    删除字符串中的所有数字。

    Args:
        content (str): 需要删除数字的字符串。

    Returns:
        str: 删除数字后的字符串。

    :param content:
    :return:
    """
    res = re.sub(r'\d', '', content)
    return res


def calculate_commission_rate(product_parser: ConfigParser, pTrade):
    """
    计算手续费
    :param product_parser:
    :param pTrade:
    :return:
    """
    # 产品
    product = del_num(pTrade['InstrumentID'])
    # 数量
    volume = pTrade['Volume']
    # 合约乘数
    volume_multiple = float(product_parser[product]["contract_multiplier"])
    # 开仓手续费率
    open_ratio_by_money = float(product_parser[product]["open_fee_rate"])
    # 开仓手续费
    open_ratio_by_volume = float(product_parser[product]["open_fee"])
    # 平仓手续费率
    close_ratio_by_money = float(product_parser[product]["close_fee_rate"])
    # 平仓手续费
    close_ratio_by_volume = float(product_parser[product]["close_fee"])
    # 平今手续费率
    close_today_ratio_by_money = float(product_parser[product]["close_today_fee_rate"])
    # 平今手续费
    close_today_ratio_by_volume = float(product_parser[product]["close_today_fee"])

    fee = 'fee'

    # 这个信号是根据下单来决定的，填的平仓，实际平的是今仓，但是回报里是平仓，会按照平仓进行计算，有的时候会造成错误
    # 比如，m合约，平今手续费0.1，平昨是0.2
    # 开仓
    if pTrade.OffsetFlag == '0':
        fee = volume * (pTrade.Price * volume_multiple * open_ratio_by_money + open_ratio_by_volume)
        pass
    # 平仓
    elif pTrade.OffsetFlag == '1':
        fee = volume * (pTrade.Price * volume_multiple * close_ratio_by_money + close_ratio_by_volume)
        pass
    # 强平
    elif pTrade.OffsetFlag == '2':
        pass
    # 平今
    elif pTrade.OffsetFlag == '3':
        fee = volume * (pTrade.Price * volume_multiple * close_today_ratio_by_money + close_today_ratio_by_volume)
        pass
    # 平昨
    elif pTrade.OffsetFlag == '4':
        fee = volume * (pTrade.Price * volume_multiple * close_ratio_by_money + close_ratio_by_volume)
        pass

    return fee


def extract_ho_symbol(ho_symbol: str) -> tuple[str, Exchange]:
    """
    :return: (symbol, exchange)
    """
    symbol, exchange_str = ho_symbol.rsplit(".", 1)
    return symbol, Exchange(exchange_str)


def generate_ho_symbol(symbol: str, exchange: Exchange) -> str:
    """
    return ho_symbol
    """
    return f"{symbol}.{exchange.value}"


def _get_trader_dir(temp_name: str) -> tuple[Path, Path]:
    """
    Get path where trader is running in.
    """
    cwd: Path = Path.cwd()
    temp_path: Path = cwd.joinpath(temp_name)

    # If folder exists in current working directory,
    # then use it as trader running path.
    if temp_path.exists():
        return cwd, temp_path

    # Otherwise use home path of system.
    home_path: Path = Path.home()
    temp_path = home_path.joinpath(temp_name)

    # Create folder under home path if not exist.
    if not temp_path.exists():
        temp_path.mkdir()

    return home_path, temp_path


TRADER_DIR, TEMP_DIR = _get_trader_dir(f".{Params.project_name}")
sys.path.append(str(TRADER_DIR))


def get_file_path(filename: str) -> Path:
    """
    Get path for temp file with filename.
    """
    return TEMP_DIR.joinpath(filename)


def get_folder_path(folder_name: str) -> Path:
    """
    Get path for temp folder with folder name.
    """
    folder_path: Path = TEMP_DIR.joinpath(folder_name)
    if not folder_path.exists():
        folder_path.mkdir()
    return folder_path


def load_json(filename: str) -> dict:
    """
    Load data from json file in temp path.
    """
    filepath: Path = get_file_path(filename)

    if filepath.exists():
        with open(filepath, encoding="UTF-8") as f:
            data: dict = json.load(f)
        return data
    else:
        save_json(filename, {})
        return {}


def save_json(filename: str, data: dict) -> None:
    """
    Save data into json file in temp path.
    """
    filepath: Path = get_file_path(filename)
    with open(filepath, mode="w+", encoding="UTF-8") as f:
        json_data = json.dumps(data, indent=4, ensure_ascii=False)
        f.write(json_data)


def round_to(value: float, target: float) -> float:
    """
    Round price to price tick value.
    """
    decimal_value: Decimal = Decimal(str(value))
    decimal_target: Decimal = Decimal(str(target))
    rounded: float = float(int(round(decimal_value / decimal_target)) * decimal_target)
    return rounded


def floor_to(value: float, target: float) -> float:
    """
    Similar to math.floor function, but to target float number.
    """
    decimal_value: Decimal = Decimal(str(value))
    decimal_target: Decimal = Decimal(str(target))
    result: float = float(int(floor(decimal_value / decimal_target)) * decimal_target)
    return result


def ceil_to(value: float, target: float) -> float:
    """
    Similar to math.ceil function, but to target float number.
    """
    decimal_value: Decimal = Decimal(str(value))
    decimal_target: Decimal = Decimal(str(target))
    result: float = float(int(ceil(decimal_value / decimal_target)) * decimal_target)
    return result


def get_digits(value: float) -> int:
    """
    Get number of digits after decimal point.
    """
    value_str: str = str(value)

    if "e-" in value_str:
        _, buf = value_str.split("e-")
        return int(buf)
    elif "." in value_str:
        _, buf = value_str.split(".")
        return len(buf)
    else:
        return 0
